package gnss

import (
	"bytes"
	"dgo/goutils/utils"
	"encoding/binary"
	"fmt"
	"time"
)

/*
 */
type Rtcm3RawBufDecoder struct {
	Id               string
	buf              []byte
	size             uint16 // 数据长度
	reserved         byte
	rawlen           uint16 // rtcm数据体长度
	Tag              int
	ErrCode          int
	OutputWarning    bool
	LogTypeStr       string
	decode_step      int
	CopyBufOnRtcmBuf bool
	OnErr            func(errcode int, err error) bool

	/**
	  rtcmBuf 可以异步调用
	*/
	OnRtcmBuf func(rtcmBuf []byte)
}

func NewRtcm32RawBufDecoder(Id string) *Rtcm3RawBufDecoder {
	return &Rtcm3RawBufDecoder{
		Id:               Id,
		buf:              make([]byte, MAX_RTCM3_RAW_SIZE, MAX_RTCM3_RAW_SIZE),
		size:             0,
		rawlen:           0,
		decode_step:      -1,
		OutputWarning:    true,
		CopyBufOnRtcmBuf: true,
	}
}

func (this *Rtcm3RawBufDecoder) Reset() {
	// this.buf = make([]byte, MAX_RTCM3_RAW_SIZE, MAX_RTCM3_RAW_SIZE)
	this.size = 0
	this.rawlen = 0
}

func (this *Rtcm3RawBufDecoder) ResetDecodeStep() {
	this.decode_step = -1
}

func (this *Rtcm3RawBufDecoder) GetRawLen() uint16 {
	return this.rawlen
}

func (this *Rtcm3RawBufDecoder) GetRtcmMsgBuf() []byte {
	return this.buf[3 : this.rawlen+3]
}

/*
*

	获取整个RtcmBuf 包括 头和CRC
*/
func (this *Rtcm3RawBufDecoder) GetRawBuf() []byte {
	return this.buf[0:this.size]
}

func (this *Rtcm3RawBufDecoder) GetSize() uint16 {
	return this.size
}

func (this *Rtcm3RawBufDecoder) GetMsgID() uint16 {
	msgid := GetBitU16(this.buf, 24, 12)
	return msgid
}

/*
*

	  Multiple Message Bit DF393

		1 indicates that more MSMs follow for given physical time and
		reference station ID
		0 indicates that it is the last MSM for given physical time and reference
		station ID
*/
func (this *Rtcm3RawBufDecoder) GetMsmSyncFlag() byte {
	return GetBitU8(this.buf, 24+12+12+30, 1)
}

func (this *Rtcm3RawBufDecoder) DecodeTime(t time.Time) (time.Time, bool) {
	msgid := int(this.GetMsgID())
	if RtcmIsObsMsm(int(this.GetMsgID())) {
		navisys := MsgID2NaviSys(msgid)
		return DecodeRtcmBufTime(this.buf, 24, navisys, t), true
	}
	return utils.ZeroTime, false
}

func (this *Rtcm3RawBufDecoder) BufAsHexStr(spliter string) string {
	return utils.BufToHexStr(this.buf[:int(this.size)], 0, spliter)
}

func (this *Rtcm3RawBufDecoder) InputBuf(buf []byte) {
	for i := 0; i < len(buf); i++ {
		this.InputByte(buf[i])
	}
}

/*
Table 4-1 Version 3 Frame Structure
Preamble 8 bits
Reserved 6 bits

	The next six bits are reserved and should be set to zero by the Transport Layer Control for all messages.
	The mobile user receiver should ignore these bits and not assume they will always be set to zero.
	  In future versions these bits may contain the version number of the standard.

Message Length: 10bits
Variable Length Data Message: 0~1023 bytes
CRC: 24bits

	-2:CRC错误
*/
func (this *Rtcm3RawBufDecoder) innerInputByte(b byte) int {
	if this.decode_step == -1 {
		this.decode_step = 0
		this.Reset()
	}

	// The Preamble is a fixed 8-bit sequence.
	if this.size == 0 { // 11010011
		this.buf[this.size] = b
		this.size++
		if b != 0xD3 {
			this.decode_step = -1
			return RTCM_NEED_MORE
		}
		return RTCM_NEED_MORE
	} else if this.size == 1 {
		/*
			The next six bits are reserved and should be set to zero by the Transport Layer Control for all messages.
			The mobile user receiver should ignore these bits and not assume they will always be set to zero.
			   In future versions these bits may contain the version number of the standard.
		*/

		this.buf[this.size] = b
		this.size++
		this.reserved = b >> 2

		//  Not defined – set to 000000 不一定是0
		//if (b) > 3 { // 后两位是长度
		//	this.decode_step = -1
		//	return RTCM_ERROR_DATA
		//}
		return RTCM_NEED_MORE
	} else if this.size == 3 {
		this.buf[this.size] = b
		this.size++

		len := binary.BigEndian.Uint16(this.buf[1:])
		this.rawlen = uint16(int(len) & 0x3FF) // 0x3FF 1111111111  1023
		return RTCM_NEED_MORE
	} else {
		this.buf[this.size] = b
		this.size++
		if this.size >= MAX_RTCM3_RAW_SIZE {
			this.decode_step = -1
			return RTCM_ERROR_DATA
		}

		if this.size == this.rawlen+6 { // 完整Buff
			crc1 := utils.CRC24QBuf(this.buf[0 : this.size-3])
			crc := GetBitU(this.buf[this.size-3:], 0, 24)
			if crc1 == crc {
				if this.OnRtcmBuf != nil {
					if this.CopyBufOnRtcmBuf {
						cpyBuf := bytes.Clone(this.GetRawBuf())
						this.OnRtcmBuf(cpyBuf)
					} else {
						this.OnRtcmBuf(this.GetRawBuf())
					}
				}
				this.decode_step = -1
				return RTCM_OK
			} else {
				this.decode_step = -1
				return RTCM_CRC_FAIL
			}
		}
		return RTCM_NEED_MORE
	}
}

/*
*

	-2:CRC错误
*/
func (this *Rtcm3RawBufDecoder) InputByte(b byte) int {
	r := this.innerInputByte(b)
	if r == RTCM_CRC_FAIL || r == RTCM_ERROR_DATA {
		searchBuf := this.buf[1:this.size]
		idx := bytes.IndexByte(searchBuf, 0xD3) // 检测是否有标记
		if idx == -1 {
			if r == RTCM_CRC_FAIL {
				if this.OnErr != nil {
					this.OnErr(RTCM_CRC_FAIL, fmt.Errorf("%sCRC校验失败, rtcmBuf:%s", utils.JoinIfNoEmpty(this.Id, "[", this.Id, "]"), this.BufAsHexStr("")))
				}
			} else if r == RTCM_ERROR_DATA {
				if this.OnErr != nil {
					if this.rawlen > 0 {
						this.OnErr(RTCM_BUG_DATA, fmt.Errorf("%s数据错误,长度:%d, msgl:%d, 最大允许长度:%d, rtcmBuf:%s",
							utils.JoinIfNoEmpty(this.Id, "[", this.Id, "]"), this.size, this.rawlen, MAX_RTCM3_RAW_SIZE, this.BufAsHexStr("")))
					} else {
						this.OnErr(RTCM_BUG_DATA, fmt.Errorf("%s数据错误,长度:%d, rtcmBuf:%s",
							utils.JoinIfNoEmpty(this.Id, "[", this.Id, "]"), this.size, this.BufAsHexStr("")))
					}
				}
			}
			return r
		}
		var tmpBuf []byte
		tmpBuf = append(tmpBuf, searchBuf[idx:]...)
		for i := 0; i < len(tmpBuf); i++ {
			r = this.InputByte(tmpBuf[i])
		}
		return r
	}
	return r
}

/*
**

	返回值:
	   RTCM_ERROR_DATA, RTCM_CRC_FAIL, RTCM_OK
*/
func (this *Rtcm3RawBufDecoder) InputRtcmBuf(buf []byte, start, l int) int {
	if buf[start] != 0xD3 {
		return RTCM_ERROR_DATA
	}
	i := start
	i += 1
	l1 := binary.BigEndian.Uint16(buf[i:])
	l1 = uint16(int(l1) & 0x3FF) // 0x3FF 1111111111  1023
	if (int(l1) + 6) != l {
		return RTCM_ERROR_DATA
	}

	crc1 := utils.CRC24QBuf(buf[start : l-3])
	crc := GetBitU(buf[start+l-3:], 0, 24)
	if crc1 == crc {
		copy(this.buf, buf[start:l])
		this.rawlen = l1
		this.size = uint16(l)
		return RTCM_OK
	} else {
		if this.OnErr != nil {
			this.OnErr(-1, fmt.Errorf("CRC校验失败,%d!=%d, rtcmBuf:%v", crc1, crc, buf[start:l]))
		} else if this.OutputWarning {
			utils.Log.Warnf("CRC校验失败,%d!=%d, rtcmBuf:%v", crc1, crc, buf[start:l])
		}
		return RTCM_CRC_FAIL
	}

}
